#include "SpawnPointBehavior.h"
#include "SetDestinationEvent.h"
#include "DestinationReachedEvent.h"
#include "AddDestinationEvent.h"
#include "System.h"
#include "GlobalTimer.h"
#include "CameraNode.h"
#include "Game.h"
#include "GraphicalComponent.h"
#include "OrientationComponent.h"
#include "SelectableComponent.h"
#include "RigidBodyComponent.h"
#include "CombatComponent.h"
#include "StatusComponent.h"
#include "Library.h"
#include "BoundingSphere.h"
#include "PhysicsTask.h"
#include "UpdateTask.h"
#include "MinionBehavior.h"
#include "MeleeAutoAttack.h"
#include "HealthCondition.h"

#define SECONDS_BETWEEN_SPAWNS	30
#define SPAWN_COUNT				2
#define SECONDS_BETWEEN_ENTITY  2

REGISTERBEHAVIOR(SpawnPointBehavior, Create);

Pointer<IBehavior> SpawnPointBehavior::Create( EntityController* controller )
{
	Pointer<SpawnPointBehavior> spawnPoint = new SpawnPointBehavior(controller);
	Pointer<IBehavior> behavior;
	CopyPointer(spawnPoint, behavior);
	
	controller->Behavior( behavior );
	controller->RegisterHandler(AddDestinationEvent::type, new CEventHandler<SpawnPointBehavior>(spawnPoint, &SpawnPointBehavior::AddDestination));
	return behavior;
}

const HashedString SpawnPointBehavior::type("SpawnPointBehavior");

const HashedString& SpawnPointBehavior::Type() const
{
	return type;
}
SpawnPointBehavior::SpawnPointBehavior( EntityController* controller ) : IBehavior(controller), m_spawning(false), m_spawnCounter(0), m_secondsBetweenSpawns(SECONDS_BETWEEN_SPAWNS), m_spawnCount(SPAWN_COUNT), m_secondsBetweenEntity(SECONDS_BETWEEN_ENTITY)
{
	Maths::Vector3D destination;

	m_controller->getPosition(destination);
	m_controller->UpdateDestination(destination);
	m_controller->UpdatePath();
}
//bool SpawnPointBehavior::Destination( IEvent& event )
//{
//	if (event.Type() == SetDestinationEvent::type)
//	{
//		SetDestinationEvent& setDestination = static_cast<SetDestinationEvent&>(event);
//		
//		Maths::Vector3D destination = setDestination.Destination();
//
//		m_controller->UpdateDestination(destination);
//		m_controller->UpdatePath();	
//	}
//	return false;
//}
//bool SpawnPointBehavior::DestinationReached( IEvent& event )
//{
//	if (event.Type() == DestinationReachedEvent::type)
//	{
//		std::list<Maths::Vector3D>& waypoints = m_controller->getWaypoints();
//		if (waypoints.size() > 0)
//		{
//			Maths::Vector3D next = waypoints.front();
//			waypoints.pop_front();
//
//			m_controller->ReceiveEvent(SetDestinationEvent(next));
//		}
//	}
//	return false;
//}
void SpawnPointBehavior::EnemyGroupName( HashedString name )
{
	m_enemyGroupName = name;
}
void SpawnPointBehavior::GroupName( HashedString name )
{
	m_groupName = name;
}
bool SpawnPointBehavior::AddDestination( IEvent& event )
{
	if (event.Type() == AddDestinationEvent::type)
	{
		AddDestinationEvent& addDestination = static_cast<AddDestinationEvent&>(event);
		Maths::Vector3D destination = addDestination.Destination();

		std::list<Maths::Vector3D>& waypoints = m_controller->getWaypoints();
		waypoints.push_back(destination);
	}
	return false;
}

void SpawnPointBehavior::Update()
{	
	if (!m_spawning)
	{
		if (GlobalTimer::getTime().getSecondsSinceStart() > (m_time.getSecondsSinceStart() + m_secondsBetweenSpawns))
		{
			m_spawning = true;
			m_time = GlobalTimer::getTime();
			m_spawnCounter = 0;
		}
	}
	if (m_spawning)
	{
		if (GlobalTimer::getTime().getSecondsSinceStart() > (m_time.getSecondsSinceStart() + m_secondsBetweenEntity))
		{
			Pointer<EntityController> controller;
			Pointer<Entity> entity;

			Game::getSingleton().CreateEntity(m_avatar, entity);
			Game::getSingleton().RetrieveController(entity, controller);
			Game::getSingleton().SetEntitySelectable(entity);
			Game::getSingleton().SetEntityGroup(m_groupName, entity);

			Pointer<INode> sun;
			OrientationComponent* orientation = (OrientationComponent*)entity->FindComponent(OrientationComponent::type);
			Game::getSingleton().RetrieveNode("Sun", sun);
			sun->Push_Back(orientation->getTransformNode());
			Game::getSingleton().AddEntityToPathingWorld(m_spawnIntoWorld, entity);
			Game::getSingleton().AddEntityToSimulationWorld(m_spawnIntoWorld, entity);
			
			
			if (controller->Behavior()->Type() == MinionBehavior::type)
			{
				Maths::Vector3D position(100,0,100);
				MinionBehavior* minion = ((MinionBehavior*)(IBehavior*)(controller->Behavior()));

				std::list<Maths::Vector3D>& waypoints = controller->getWaypoints();
				waypoints = m_controller->getWaypoints();
		
				minion->EnemyGroup(m_enemyGroupName);
				
				m_controller->getPosition(position);
				controller->UpdatePosition(position);
				
				minion->DestinationReached(DestinationReachedEvent());
			}


			m_time = GlobalTimer::getTime();
			++m_spawnCounter;
			if (m_spawnCounter >= SPAWN_COUNT)
			{
				m_spawning = false;
			}
		}
	}
}

void SpawnPointBehavior::SpawnIntoWorld( HashedString world )
{
	m_spawnIntoWorld = world;
}

bool SpawnPointBehavior::ToXML( tinyxml2::XMLPrinter& printer )
{
	printer.OpenElement("SpawnPointBehavior");

	printer.PushAttribute("Avatar", m_avatar.getString().c_str());
	printer.PushAttribute("World", m_spawnIntoWorld.getString().c_str());
	printer.PushAttribute("EnemyGroupName", m_enemyGroupName.getString().c_str());
	printer.PushAttribute("GroupName", m_groupName.getString().c_str());
	printer.PushAttribute("SecondsBetweenEntity", m_secondsBetweenEntity);
	printer.PushAttribute("SecondsBetweenSpawns", m_secondsBetweenSpawns);
	printer.PushAttribute("Spawning", m_spawning);
	printer.PushAttribute("SpawnCount", m_spawnCount);
	printer.PushAttribute("SpawnCounter", m_spawnCounter);
	printer.PushAttribute("SpawnTime", m_time.getMilliSecondsSinceStart());

	printer.CloseElement();
	return true;
}

bool SpawnPointBehavior::FromXML( tinyxml2::XMLElement* behaviorElement )
{
	m_avatar = HashedString(behaviorElement->Attribute("GroupName"));
	m_spawnIntoWorld = HashedString(behaviorElement->Attribute("World"));
	m_enemyGroupName = HashedString(behaviorElement->Attribute("EnemyGroupName"));
	m_groupName = HashedString(behaviorElement->Attribute("GroupName"));
	m_secondsBetweenEntity = behaviorElement->FloatAttribute("SecondsBetweenEntity");
	m_secondsBetweenSpawns = behaviorElement->FloatAttribute("SecondsBetweenSpawns");
	m_spawning = behaviorElement->BoolAttribute("Spawning");
	m_spawnCount = behaviorElement->UnsignedAttribute("SpawnCount");
	m_spawnCounter = behaviorElement->UnsignedAttribute("SpawnCounter");
	m_time.getMilliSecondsSinceStart() = behaviorElement->FloatAttribute("SpawnTime");

	return true;
}